/*
 * @Date: 2023-03-15 17:20:30
 * @LastEditTime: 2023-03-24 16:36:05
 * @FilePath: /NLK/src/sdk/tronWeb.ts
 * 介绍:波场链sdk
 */
import { sdkSucceed, sdkFail, SdkRes } from "./index";
import { TronLinkAdapter } from "@tronweb3/tronwallet-adapters";
import { TronWeb } from "tronweb.types";
import tronAbi from "./abi/tronAbi";
import { parseAmount, parseBalance } from "./index";

const adapter = new TronLinkAdapter();
const tronweb = window.tronWeb as unknown as TronWeb & AnyObject;
/**连接钱包 */
export function sdkConnect() {
  return new Promise<SdkRes<string>>((resolve) => {
    try {
      if (!window.tronWeb) return resolve(sdkFail("请切换波场链后再尝试连接"));
      adapter
        .connect()
        .then(() => {
          resolve(sdkSucceed("连接钱包", adapter.address));
        })
        .catch((error) => {
          resolve(sdkFail(error.message, error));
        });
    } catch (error: any) {
      resolve(sdkFail("意料之外" + error.message, error));
    }
  });
}
export function sdkGetAddress(): string {
  return adapter.address!;
}

/**判断是否波场 */
export function sdkIsTron() {
  return Boolean(window.tronWeb);
}
/**
 * * 授权
 * @param mint 授权合约地址
 * @param amount 支付金额
 * @param format 精度
 * @param toAddress 授权地址
 * @returns
 */
export function sdkApprove(
  mint: string,
  amount: number,
  format: number,
  toAddress: string
) {
  return new Promise<SdkRes<string>>((resolve) => {
    const value = parseAmount(amount, format);
    console.log("授权");
    console.log("omit", mint);
    console.log("amount", amount);
    console.log("format", format);
    console.log("value", value);
    console.log("toAddress", toAddress);

    const contract = tronweb.contract(tronAbi as any, mint);
    let send: any;
    if (!contract.methods.increaseAllowance)
      send = contract.methods.approve(toAddress, value).send;
    else send = contract.methods.increaseAllowance(toAddress, value).send;
    send({
      feeLimit: 100000000,
    } as any)
      .then(sussend)
      .catch((error: any) => {
        resolve(sdkFail(error.message, error));
      });

    function sussend(res: string) {
      resolve(sdkSucceed("授权", res));
    }
  });
}
/**
 * * 发起代币转账
 * @param mint 合约地址
 * @param amount 付款金额
 * @param format 精度
 * @param toAddress 收款地址
 */
export function sdkTransferToken(
  mint: string,
  amount: number,
  format: number,
  toAddress: string
) {
  return new Promise<SdkRes<string>>(async (resolve) => {
    const value = parseAmount(amount, format);
    console.log("代币转账");
    console.log("amount", amount, "format", format, "value", value);
    console.log("mint", mint);
    console.log("toAddress", toAddress);
    const contract = tronweb.contract(tronAbi as any, mint);
    contract.methods
      .transfer(toAddress, value)
      .send()
      .then((res) => {
        resolve(sdkSucceed("代币转账", res));
      })
      .catch((error) => {
        console.log("代币转账");
        resolve(sdkFail(error.message || error, error));
      });
  });
}

/**
 * * 发起主币转账
 * @param amount 转账金额
 * @param format 精度
 * @param toAddress 收款方地址
 * @returns
 */
export function sdkTransfer(amount: number, format: number, toAddress: string) {
  return new Promise<SdkRes<string>>((resolve) => {
    const value = parseAmount(amount, format);
    console.log("主币转账");
    console.log("amount", amount, "format", format, "value", Number(value));
    console.log("toAddress", toAddress);
    console.log("创建交易");
    const transactionBuilder: any = tronweb.transactionBuilder;
    transactionBuilder
      .sendTrx(toAddress, value)
      .then(signTransfer)
      .catch((error: any) => {
        resolve(sdkFail(error.message, error));
      });

    /**
     * * 签名交易
     * @param res 创建好的交易实例
     */
    function signTransfer(res: any) {
      console.log("签名交易");
      const trx: any = tronweb.trx;
      trx
        .sign(res)
        .then(sendTransfer)
        .catch((error: any) => {
          resolve(sdkFail(error.message, error));
        });
    }
    /**
     * * 广播交易
     * @param res 签名好的交易
     */
    function sendTransfer(res: any) {
      console.log("签名交易所有数据结果", res);
      console.log("广播交易");
      const trx: any = tronweb.trx;
      trx.sendRawTransaction(res).then((res: any) => {
        console.log("广播交易全部数据结果", res);
        resolve(sdkSucceed("主币转账", res.transaction.txID));
      });
    }
  });
}

/**
 * * 查询tron主币余额
 * @param format 精度
 * @param findAddress 持有用户地址
 * @returns
 */
export function sdkFindBalance(format: number, findAddress = adapter.address) {
  return new Promise<SdkRes<number>>((resolve) => {
    console.log("查询trx余额");
    if (!findAddress) return resolve(sdkFail("获取用户地址失败", adapter));
    tronweb.trx
      .getBalance(findAddress)
      .then((res) => {
        resolve(sdkSucceed("查询trx余额", parseBalance(res, format)));
      })
      .catch((err) => {
        resolve(sdkFail(err.message, err));
      });
  });
}

/**
 * * 查询代币余额
 * @param mint 合约地址
 * @param format 精度
 * @param findAddress 持有用户地址
 * @returns
 */
export function sdkFindTokenBalance(
  mint: string,
  format: number,
  findAddress = adapter.address
) {
  return new Promise<SdkRes<number>>((resolve) => {
    const tronWeb: AnyObject = window.tronWeb as any;
    if (!findAddress) return resolve(sdkFail("获取用户地址失败", adapter));
    console.log("查询代币余额", findAddress);
    //* 构建代币信息
    console.log("构建代币信息");
    tronWeb
      .contract()
      .at(mint)
      .then(balanceOf)
      .catch((error: any) => {
        resolve(sdkFail(error.message, error));
      });
    /**
     * * 查询代币余额
     * @param res 构建代币信息结果
     */
    function balanceOf(res: any) {
      console.log("查询代币余额");
      res
        .balanceOf(findAddress)
        .call()
        .then((res: any) => {
          console.log("查询代币余额完整结果", res);
          resolve(
            sdkSucceed("查询代币余额", parseBalance(parseInt(res._hex), format))
          );
        })
        .catch((error: any) => {
          resolve(sdkFail(error.message, error));
        });
    }
  });
}
/**
 * * 自动区分查询主币代币余额
 * @param mint 合约地址
 * @param format 精度
 * @param findAddress 持有用户地址
 * @returns
 */
export function sdkAutoFindBalance(
  mint: string | undefined | null,
  format: number,
  findAddress?: string
) {
  if (mint) return sdkFindTokenBalance(mint, format, findAddress);
  return sdkFindBalance(format, findAddress);
}
